#include <fcntl.h>
#include <router/RouterClient.h>
#include <router/RouterServer.h>

RouterClient::RouterClient(uint16_t ctl_port):
    ep(4096)
{
    set_controller(ctl_port);
}

void RouterClient::set_user_host(uint32_t user, uint32_t host)
{
    this->user_id = user;
    this->host_id = host;
}

std::shared_ptr<App> RouterClient::get_app(uint32_t id)
{
    if (app_table.count(id) == 0)
        return nullptr;
    return app_table[id];
}

uint32_t RouterClient::get_app_id(std::shared_ptr<App> app)
{
    if (id_table.count(app) == 0)
        return 0;
    return id_table[app];
}

std::shared_ptr<RouterControlServer> RouterClient::get_controller()
{
    return std::static_pointer_cast<RouterControlServer>(app_table[CONTROLLER_ID]);
}

void RouterClient::set_controller(uint32_t ctl_port)
{
    std::shared_ptr<RouterControlServer> controller = std::make_shared<RouterControlServer>(ctl_port);

    app_table[CONTROLLER_ID] = controller;
    id_table[controller] = CONTROLLER_ID;

    // controller->set_sender({get_user_id(), get_host_id(), CONTROLLER_ID});
    // controller->set_receiver(RouterServer::SERVER_ENDPOINT);
}

uint32_t RouterClient::register_app(std::shared_ptr<App> app)
{
    if (id_table.count(app))
        return id_table[app];
    while (app_id == ROUTERCLIENT_ID || app_id == CONTROLLER_ID || app_table.count(app_id))
        app_id++;

    app_table[app_id] = app;
    id_table[app] = app_id;

    epoll_data_t ep_data;
    ep_data.u32 = app_id;
    ep.epoll_add(static_cast<EPOLL_EVENTS>(EPOLLIN | EPOLLET), app->get_fd(), ep_data);

    app->set_sender({get_user_id(), get_host_id(), app_id});
    return app_id++;
}

void RouterClient::unregister_app(std::shared_ptr<App> app)
{
    if (id_table.count(app) == 0)
        return;
    uint32_t id = id_table[app];
    id_table.erase(app);
    app_table.erase(id);
    ep.epoll_del(app->get_fd());
}

uint32_t RouterClient::get_user_id()
{
    return user_id;
}

uint32_t RouterClient::get_host_id()
{
    return host_id;
}

void RouterClient::start(std::string_view server_ip, uint16_t server_port)
{
    client.set_server_addr(server_ip, server_port);
    client.connect();

    epoll_data_t data;

    int flags = fcntl(client.get_sockfd(), F_GETFL, 0);
    fcntl(client.get_sockfd(), F_SETFL, flags | O_NONBLOCK);
    data.u32 = ROUTERCLIENT_ID;
    ep.epoll_add(static_cast<EPOLL_EVENTS>(EPOLLIN | EPOLLET), client.get_sockfd(), data);

    flags = fcntl(routerctl.get_sockfd(), F_GETFL, 0);
    fcntl(routerctl.get_sockfd(), F_SETFL, flags | O_NONBLOCK);
    data.u32 = CONTROLLER_ID;
    ep.epoll_add(static_cast<EPOLL_EVENTS>(EPOLLIN | EPOLLET), routerctl.get_sockfd(), data);


    thread_pool.start();
    read_thread = std::thread(&RouterClient::read_thread_func, this);
    write_thread = std::thread(&RouterClient::write_thread_func, this);
}

void RouterClient::wait()
{
    read_thread.join();
    write_thread.join();
}

void RouterClient::read_thread_func()
{
    // 只需要额外开一个线程 负责写操作即可
    while (true)
    {
        int events_count = ep.epoll_wait(-1);
        if (events_count == -1)
        {
            perror("本次epoll_wait过程中发生了错误");
            continue;
        }

        for (int i = 0; i < events_count; ++i)
            thread_pool.submit(read_from_fd, this, ep[i].data);
    }
}

void RouterClient::write_thread_func()
{
    while (true)
    {
        message msg = message_send_queue.poll();
        Endpoint receiver = msg.get_router_info().to;
        // 如果是发送给本机的应用
        if (receiver.user == get_user_id() && receiver.host == get_host_id()){
            std::shared_ptr<App> app = app_table[receiver.app];
            app->message_hander(msg);
        }
        else{
            auto from = msg.get_router_info().from;
            auto to = msg.get_router_info().to;
            message::write_message_to(msg, client.get_sockfd());
        }
    }
}

void RouterClient::put_message(message msg)
{
    message_send_queue.push(msg);
}

void RouterClient::read_from_fd(RouterClient* router, epoll_data_t data)
{
    if (data.u32 == ROUTERCLIENT_ID){
        auto [msg, is_valid] = message::read_message_from(router->client.get_sockfd());
        if (is_valid == false){
            perror("与服务器断开连接");
            return;
        }

        std::shared_ptr<App> app = router->app_table[msg.get_router_info().to.app];
        app->message_hander(msg);
        return;
    }

    std::shared_ptr<App> app = router->app_table[data.u32];
    app->fd_hander();
}

 